/* 
 * File:   AgentDB.cpp
 * Author: eduardo
 *
 * Created on 18 de noviembre de 2012, 20:28
 */

#include "AgentDB.h"

AgentDB* AgentDB::_agent = NULL;

AgentDB::AgentDB() {
}

AgentDB* AgentDB::getAgentePtr() {
    if (!_agent) {
        cout << "No hay instancia previa del Agente; creando..." << endl;
        _agent = new AgentDB();
    }
    return _agent;
}

void AgentDB::create_database(int& argc, char* argv[]) {
    _db = new odb::mysql::database(argc, argv);
}

int AgentDB::existTerm(const string& term) {
    int ret = 0;
    typedef odb::query<DictionaryDB> query;
    typedef odb::result<DictionaryDB> result;

    try {
        transaction t(_db->begin());

        result r(_db->query<DictionaryDB > (query::term == term));
        result::iterator i(r.begin());
        if (i != r.end()) ret = 1;

        t.commit();
    } catch (const odb::exception& e) {
        cerr << "Exists term.: " << e.what() << endl;
    }

    return ret;
}

void AgentDB::persistDictTerm(const string& term, int idT) {
    try {
        transaction t(_db->begin());

        // Make object
        DictionaryDB d(term, idT);

        // Make objects persistent
        _db->persist(d);

        t.commit();
    } catch (const odb::exception& e) {
        cerr << "Persist Dict. Term.: " << e.what() << endl;
    }
}

void AgentDB::persistPFLine(int idPF, const vector<DocOccurrence>& vec) {
    try {
        transaction t(_db->begin());

        // Make object
        PostingFileDB d(idPF, vec);

        // Make objects persistent
        _db->persist(d);

        t.commit();
    } catch (const odb::exception& e) {
        cerr << "Persist PF Line: " << e.what() << endl;
    }
}

void AgentDB::persistIDDoc(int id, const string& name) {
    typedef odb::query<IdDocs> query;
    typedef odb::result<IdDocs> result;

    try {
        transaction t(_db->begin());

        result r(_db->query<IdDocs > (query::id == id));
        if (r.begin() == r.end()) {
            IdDocs doc(id, name);
            _db->persist(doc);
        }

        t.commit();
    } catch (const odb::exception& e) {
        cerr << "Persist ID Docs: " << e.what() << endl;
    }
}

void AgentDB::updateTerm(const string& term, const vector<DocOccurrence>& newvec) {
    try {
        transaction t(_db->begin());

        auto_ptr<DictionaryDB> dict(_db->load <DictionaryDB > (term));
        auto_ptr<PostingFileDB> PFDB(_db->load<PostingFileDB > (dict->getIDPF()));
        for (int i = 0; i < newvec.size(); i++) {
            PFDB->pushBack(newvec.at(i));
        }
        _db->update(*PFDB);

        t.commit();
    } catch (const odb::exception& e) {
        cerr << "Update Term.: " << e.what() << endl;
    }
}

void AgentDB::getIdDocs(const string& term, set<int>* iddocs) {
    try {
        transaction t(_db->begin());

        auto_ptr<DictionaryDB> dict(_db->load <DictionaryDB > (term));
        auto_ptr<PostingFileDB> PFDB(_db->load<PostingFileDB > (dict->getIDPF()));
        vector<DocOccurrence> docs = PFDB->getOccurrences();
        for (int i = 0; i < docs.size(); i++) {
            iddocs->insert(docs.at(i).getDoc());
        }
        t.commit();
    } catch (const odb::exception& e) {
        cerr << "GetIdDocs: " << e.what() << endl;
    }
}

void AgentDB::getTotalDocs(int* total) {
    typedef odb::query<IdDocs> query;
    typedef odb::result<IdDocs> result;

    try {
        transaction t(_db->begin());

        result r(_db->query<IdDocs > ());
        *total = r.size();

        t.commit();
    } catch (const odb::exception& e) {
        cerr << "GetTotalDocs: " << e.what() << endl;
    }
}

map<int, int> AgentDB::fillOccu(const string& term) const {
    try {
        transaction t(_db->begin());

        auto_ptr<DictionaryDB> dict(_db->load <DictionaryDB > (term));
        auto_ptr<PostingFileDB> PFDB(_db->load<PostingFileDB > (dict->getIDPF()));
        vector<DocOccurrence> docs = PFDB->getOccurrences();
        map<int, int> ocu;
        for (int i = 0; i < docs.size(); i++) {
            ocu[docs.at(i).getDoc()] = docs.at(i).getReps();
        }
        t.commit();
        return ocu;
    } catch (const odb::exception& e) {
        cerr << "GetIdDocs: " << e.what() << endl;
    }
}

int AgentDB::loadNTerms() {
    typedef odb::query<DictionaryDB> query;
    typedef odb::result<DictionaryDB> result;
    int total = 0;

    try {
        transaction t(_db->begin());

        result r(_db->query<DictionaryDB > ());
        for (result::iterator i(r.begin()); i != r.end(); i++) {
            if (i->getIDPF() > total) total = i->getIDPF();
        }

        t.commit();
    } catch (const odb::exception& e) {
        cerr << "loadNTerms: " << e.what() << endl;
    }

    return total + 1;
}

int AgentDB::loadNDocs() {
    typedef odb::query<IdDocs> query;
    typedef odb::result<IdDocs> result;
    int total = 0;

    try {
        transaction t(_db->begin());

        result r(_db->query<IdDocs > ());
        for (result::iterator i(r.begin()); i != r.end(); i++) {
            if (i->getID() > total) total = i->getID();
        }

        t.commit();
    } catch (const odb::exception& e) {
        cerr << "loadNDocs: " << e.what() << endl;
    }

    return total + 1;
}